package com.devunion.bogdan.view.editors;

import com.devunion.bogdan.model.project.Annotation;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;

/**
 * User: user
 * Date: 06.02.2003
 * Time: 21:40:17
 */

/**
 * Class for creating different kinds of widgets.
 * For adding new widget you need to create <code>public void createXXX()</code> method.
 * In this method you create necessary component. For ex: <code> currentComponent = new JLabel("Label") ...</code>.
 */
public class ComponentFactory implements PositionConstants {
    private Map<Component, ComponentInfo> components;
    private Point prevLocation;
    private static final int borderWidth = 2;
    private Border borderSelection = new LineBorder(Color.RED, borderWidth);

    private int cursorLocation = POSITION_UNDEFINED;

    public ComponentFactory(Map<Component, ComponentInfo> components) {
        this.components = components;
    }

    public JComponent createView(Annotation annotation) {
        JComponent view = new AnnotationView(annotation) {
            protected void paintBorder(Graphics g) {
                if (components.get(this).isSelected()) {
                    setBorder(borderSelection);
                } else {
                    setBorder(LineBorder.createBlackLineBorder());
                }
                super.paintBorder(g);
            }
        };

        addListeners(view, annotation);

        return view;
    }

    /**
     * Selected component will be returned after necessary initialization.
     * This method specify all behaviour of selected component.
     * @param view annotation view
     * @param ann annotation
     */
    private void addListeners(final JComponent view, final Annotation ann) {
        final ComponentInfo componentInfo = new ComponentInfo(view);

        view.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
//                prevLocation = e.getPoint();
//
//                if (isInLeftTopCorner(prevLocation)) {
//                    cursorLocation = POSITION_CORNER_LEFT_TOP;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
//                } else if (isInRightTopCorner(prevLocation, e.getComponent().getSize())) {
//                    cursorLocation = POSITION_CORNER_RIGHT_TOP;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
//                } else if (isInLeftBottomCorner(prevLocation, e.getComponent().getSize())) {
//                    cursorLocation = POSITION_CORNER_LEFT_BOTTOM;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
//                } else if (isInRightBottomCorner(prevLocation, e.getComponent().getSize())) {
//                    cursorLocation = POSITION_CORNER_RIGHT_BOTTOM;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
//                } else if (isOnTopBorder(prevLocation)) {
//                    cursorLocation = POSITION_TOP_BORDER;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
//                } else if (isOnBottomBorder(prevLocation, e.getComponent().getSize())) {
//                    cursorLocation = POSITION_BOTTOM_BORDER;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
//                } else if (isOnLeftBorder(prevLocation)) {
//                    cursorLocation = POSITION_LEFT_BORDER;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
//                } else if (isOnRightBorder(prevLocation, e.getComponent().getSize())) {
//                    cursorLocation = POSITION_RIGHT_BORDER;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
//                } else {
//                    cursorLocation = POSITION_UNDEFINED;
//                    e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
//                }
//
                SelectionManager selectionManager = AnnotationManager.getInstance().getSelectionManager();

                ComponentInfo realInfo = components.get(e.getComponent());
                if (e.isControlDown()) {
                    boolean newVal = !componentInfo.isSelected();
                    realInfo.setSelectedWithoutNotification(newVal);
                    selectionManager.setSelection(e.getComponent(), newVal);

                    if (componentInfo.isSelected()) {
                        ((JComponent) e.getComponent()).setBorder(borderSelection);
                    } else {
                        ((JComponent) e.getComponent()).setBorder(LineBorder.createBlackLineBorder());
                    }
                } else {
                    JComponent parent = (JComponent) e.getComponent().getParent();

                    for (int i = 0; i < parent.getComponentCount(); i++) {
                        components.get(parent.getComponent(i)).setSelectedWithoutNotification(false);
                        ((JComponent) parent.getComponent(i)).setBorder(LineBorder.createBlackLineBorder());
                    }
                    realInfo.setSelectedWithoutNotification(true);

                    selectionManager.setSelection(e.getComponent(), true);

                    ((JComponent) e.getComponent()).setBorder(borderSelection);
                }
            }
//
//            public void mouseReleased(MouseEvent e) {
//                e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
//            }
        });
//
//        view.addMouseMotionListener(new MouseMotionAdapter() {
//            public void updateModelFromView(Annotation annotation, JComponent component) {
//                AnnotationView view = (AnnotationView) component;
//
//                annotation.setLocation(view.getRealX(),  view.getRealY());
//
//                annotation.setWidth(view.getRealWidth());
//                annotation.setHeight(view.getRealHeight());
//            }
//
//            public void mouseDragged(MouseEvent e) {
//                JComponent component = (JComponent) e.getComponent();
//
//                // Resizing
//                if (cursorLocation == POSITION_CORNER_LEFT_TOP) {
//                    component.setBounds(component.getX() + e.getPoint().x - prevLocation.x,
//                            component.getY() + e.getPoint().y - prevLocation.y,
//                            component.getWidth() - e.getPoint().x + prevLocation.x,
//                            component.getHeight() - e.getPoint().y + prevLocation.y);
//
//                } else if (cursorLocation == POSITION_CORNER_RIGHT_TOP) {
//                    component.setBounds(component.getX(),
//                            component.getY() + e.getPoint().y - prevLocation.y,
//                            component.getWidth() + e.getPoint().x - prevLocation.x,
//                            component.getHeight() - e.getPoint().y + prevLocation.y);
//
//                    prevLocation = new Point(e.getPoint().x, e.getPoint().y - e.getPoint().y + prevLocation.y);
//                } else if (cursorLocation == POSITION_CORNER_LEFT_BOTTOM) {
//                    component.setBounds(component.getX() + e.getPoint().x - prevLocation.x,
//                            component.getY(),
//                            component.getWidth() - e.getPoint().x + prevLocation.x,
//                            component.getHeight() + e.getPoint().y - prevLocation.y);
//
//                    prevLocation = new Point(e.getPoint().x - e.getPoint().x + prevLocation.x, e.getPoint().y);
//                } else if (cursorLocation == POSITION_CORNER_RIGHT_BOTTOM) {
//                    component.setSize(component.getWidth() + e.getPoint().x - prevLocation.x,
//                            component.getHeight() + e.getPoint().y - prevLocation.y);
//
//                    prevLocation = e.getPoint();
///* BORDERS */
//                } else if (cursorLocation == POSITION_TOP_BORDER) {
//                    int diff = prevLocation.y - e.getPoint().y;
//
//                    component.setBounds(component.getX(),
//                            component.getY() - diff,
//                            component.getWidth(),
//                            component.getHeight() + diff);
//
//                } else if (cursorLocation == POSITION_BOTTOM_BORDER) {
//                    component.setSize(component.getWidth(),
//                            component.getHeight() + e.getPoint().y - prevLocation.y);
//
//                    prevLocation = e.getPoint();
//                } else if (cursorLocation == POSITION_LEFT_BORDER) {
//                    component.setBounds(component.getX() + e.getPoint().x - prevLocation.x,
//                            component.getY(),
//                            component.getWidth() - e.getPoint().x + prevLocation.x,
//                            component.getHeight());
//
//                } else if (cursorLocation == POSITION_RIGHT_BORDER) {
//                    component.setBounds(component.getLocation().x,
//                            component.getLocation().y,
//                            component.getBounds().width + e.getPoint().x - prevLocation.x,
//                            component.getBounds().height);
////                    component.setBounds(ann.getX(),
////                            ann.getY(),
////                            ann.getWidth() + e.getPoint().x - prevLocation.x,
////                            ann.getHeight());
//
//                    prevLocation = e.getPoint();
///* MOVING */
//                } else {
//                    if (!components.get(e.getComponent()).isSelected()) {
//                        return;
//                    }
//
//                    for (Component key : components.keySet()) {
//                        if (components.get(key).isSelected()) {
//                            int x = key.getLocation().x + e.getPoint().x - prevLocation.x;
//                            int y = key.getLocation().y + e.getPoint().y - prevLocation.y;
//
//                            key.setLocation(x, y);
//                        }
//                    }
//                }
//
//                updateModelFromView(ann, component);
//            }
//
//            public void mouseMoved(MouseEvent e) {
//
//                Cursor cursor = getCursorInCorner(e.getPoint(), ((JComponent) e.getSource()).getSize());
//                if (cursor != null) {
//                    e.getComponent().setCursor(cursor);
//                } else {
//                    cursor = getCursorOnBorder(e.getPoint(), ((JComponent) e.getSource()).getSize());
//                    if (cursor != null) {
//                        e.getComponent().setCursor(cursor);
//                    } else {
//                        e.getComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
//                    }
//                }
//            }
//        });

        view.addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                view.updateUI();
            }
        });

        componentInfo.addPropertyChangeListener("selected", new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                ((ComponentInfo) evt.getSource()).getOwner().updateUI();
            }
        });

        components.put(view, componentInfo);
    }

    private Cursor getCursorInCorner(Point p, Dimension size) {
        if (isInLeftTopCorner(p)) {
            return Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR);
        }

        if (isInRightTopCorner(p, size)) {
            return Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR);
        }

        if (isInLeftBottomCorner(p, size)) {
            return Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR);
        }

        if (isInRightBottomCorner(p, size)) {
            return Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR);
        }

        return null;
    }

    private Cursor getCursorOnBorder(Point p, Dimension size) {
        if (isOnTopBorder(p)) {
            return Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
        }

        if (isOnBottomBorder(p, size)) {
            return Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
        }

        if (isOnLeftBorder(p)) {
            return Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR);
        }

        if (isOnRightBorder(p, size)) {
            return Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
        }
        return null;
    }

    private boolean isOnTopBorder(Point p) {
        return p.y >= 0 && p.y < borderWidth;
    }

    private boolean isOnBottomBorder(Point p, Dimension size) {
        return p.y >= size.height - borderWidth && p.y < size.height;
    }

    private boolean isOnLeftBorder(Point p) {
        return p.x >= 0 && p.x < borderWidth;
    }

    private boolean isOnRightBorder(Point p, Dimension size) {
        return p.x >= size.width - borderWidth && p.x < size.width;
    }

    private boolean isInLeftTopCorner(Point p) {
        return 0 <= p.x && p.x <= borderWidth && 0 <= p.y && p.y <= borderWidth;
    }

    private boolean isInRightTopCorner(Point p, Dimension size) {
        return size.width - borderWidth <= p.x && p.x <= size.width && 0 <= p.y && p.y <= borderWidth;
    }

    private boolean isInLeftBottomCorner(Point p, Dimension size) {
        return 0 <= p.x && p.x <= borderWidth && size.height - borderWidth <= p.y && p.y <= size.height;
    }

    private boolean isInRightBottomCorner(Point p, Dimension size) {
        return size.width - borderWidth <= p.x && p.x <= size.width && size.height - borderWidth <= p.y && p.y <= size.height;
    }
}
